package com.urban.pooling.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import org.hibernate.annotations.Formula;
import org.hibernate.annotations.Type;

/**
 * The persistent class for the routes database table.
 * 
 */
@Entity
@Table(name = "routes")
@NamedQuery(name = "Route.findAll", query = "SELECT r FROM Route r")
public class Route implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "route_id", unique = true, nullable = false)
	private Integer routeId;

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "arrival_time")
	private Date arrivalTime;

	@Column(length = 45)
	private String car;

	@Column(name = "dest_address", nullable = false, length = 45)
	private String destAddress;

	/*
	 * @ManyToOne
	 * 
	 * @JoinColumn(name="dest_point", nullable=false) private GeoPoint
	 * destPoint;
	 */

	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "last_modified")
	private Date lastModified;

	@Column(nullable = false)
	private Integer seats;

	@Column(name = "start_address", nullable = false, length = 45)
	private String startAddress;

	/*
	 * @ManyToOne
	 * 
	 * @JoinColumn(name="start_point", nullable=false) private GeoPoint
	 * startPoint;
	 */
	@Temporal(TemporalType.TIMESTAMP)
	@Column(name = "start_time", nullable = false)
	private Date startTime;

	// uni-directional many-to-one association to User
	@ManyToOne
	@JoinColumn(name = "driver", nullable = false)
	private User driver;

	// bi-directional many-to-one association to GeoPoint
	@OneToMany(mappedBy = "route", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
	@OrderColumn(name = "point_order")
	private List<GeoPoint> geoPoints;

	@Transient
	//@Formula(value = "(SELECT coalesce(sum(rr.seats),0) FROM route_requests rr WHERE rr.status_id =2 AND rr.route_id = route_id)")
	private int occupiedSeats;

	@Column(name = "every_work_day")
	@Type(type = "org.hibernate.type.NumericBooleanType")
	private Boolean everyWorkDay;

	@Transient
	private List<GeoPoint> waypoints;

	public Route() {
		geoPoints = new ArrayList<GeoPoint>(2);
		occupiedSeats = 0;
		// geoPoints.add(null);//TODO : change this
		// geoPoints.add(null);
	}

	public Integer getRouteId() {
		return this.routeId;
	}

	public void setRouteId(Integer routeId) {
		this.routeId = routeId;
	}

	public Date getArrivalTime() {
		return this.arrivalTime;
	}

	public void setArrivalTime(Date arrivalTime) {
		this.arrivalTime = arrivalTime;
	}

	public String getCar() {
		return this.car;
	}

	public void setCar(String car) {
		this.car = car;
	}

	public String getDestAddress() {
		return this.destAddress;
	}

	public void setDestAddress(String destAddress) {
		this.destAddress = destAddress;
	}

	public GeoPoint getDestPoint() {
		if (geoPoints.size() >= 2) {
			return geoPoints.get(geoPoints.size() - 1);
		}
		return null;
	}

	public void setDestPoint(GeoPoint destPoint) {
		if (geoPoints.size() >= 2) {
			geoPoints.set(geoPoints.size() - 1, destPoint);
		} else if (geoPoints.size() == 1) {
			geoPoints.add(destPoint);
		} else {
			geoPoints.add(null);
			geoPoints.add(destPoint);
		}
	}

	public Date getLastModified() {
		return this.lastModified;
	}

	public void setLastModified(Date lastModified) {
		this.lastModified = lastModified;
	}

	public Integer getSeats() {
		return this.seats;
	}

	public void setSeats(Integer seats) {
		this.seats = seats;
	}

	public String getStartAddress() {
		return this.startAddress;
	}

	public void setStartAddress(String startAddress) {
		this.startAddress = startAddress;
	}

	public GeoPoint getStartPoint() {
		if (geoPoints.size() > 0) {
			return geoPoints.get(0);
		} else
			return null;
	}

	public void setStartPoint(GeoPoint startPoint) {
		if (geoPoints.size() > 0) {
			geoPoints.set(0, startPoint);
		} else {
			geoPoints.add(startPoint);
		}
	}

	public Date getStartTime() {
		return this.startTime;
	}

	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}

	public User getDriver() {
		return this.driver;
	}

	public void setDriver(User driver) {
		this.driver = driver;
	}

	public List<GeoPoint> getGeoPoints() {
		return this.geoPoints;
	}

	public void setGeoPoints(List<GeoPoint> geoPoints) {
		this.geoPoints = geoPoints;
	}

	public GeoPoint addGeoPoint(GeoPoint geoPoint) {
		getGeoPoints().add(geoPoint);
		geoPoint.setRoute(this);

		return geoPoint;
	}

	public GeoPoint removeGeoPoint(GeoPoint geoPoint) {
		getGeoPoints().remove(geoPoint);
		geoPoint.setRoute(null);

		return geoPoint;
	}

	public Integer getOccupiedSeats() {
		return occupiedSeats;
	}

	public void setOccupiedSeats(Integer occupiedSeats) {
		this.occupiedSeats = occupiedSeats;
	}

	public List<GeoPoint> getWaypoints() {
		return waypoints;
	}

	public void setWaypoints(List<GeoPoint> waypoints) {
		this.waypoints = waypoints;
	}

	public Boolean getEveryWorkDay() {
		return everyWorkDay;
	}

	public void setEveryWorkDay(Boolean everyWorkDay) {
		this.everyWorkDay = everyWorkDay;
	}

	@Override
	public String toString() {
		return "Route [routeId=" + routeId + ", arrivalTime=" + arrivalTime + ", car=" + car + ", destAddress="
				+ destAddress + ", lastModified=" + lastModified + ", seats=" + seats + ", startAddress="
				+ startAddress + ", startTime=" + startTime + ", driver=" + driver + ", geoPoints=" + geoPoints
				+ ", occupiedSeats=" + occupiedSeats + ", everyWorkDay=" + everyWorkDay + ", waypoints=" + waypoints
				+ "]";
	}

}